package com.econ.powercloud.ems.service.biz;

import com.alibaba.fastjson.JSON;
import com.econ.powercloud.ems.common.enums.DitTypeEnum;
import com.econ.powercloud.ems.common.enums.MeasureType;
import com.econ.powercloud.ems.common.enums.TimeIntervalType;
import com.econ.powercloud.ems.common.util.DateTimeUtil;
import com.econ.powercloud.ems.constant.SysConstant;
import com.econ.powercloud.ems.pojo.*;
import com.econ.powercloud.ems.pojo.requestVO.EmsHisDataRequestVO;
import com.econ.powercloud.ems.pojo.scene.HisDataPidsVO;
import com.econ.powercloud.ems.pojo.scene.HisDataRequestVO;
import com.econ.powercloud.ems.pojo.scene.OpenApiHisDataVO;
import com.econ.powercloud.ems.service.common.QueryHisDataCommonService;
import com.econ.powercloud.ems.util.TimeUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Component;

import java.util.*;
import java.text.SimpleDateFormat;
import java.util.stream.Collectors;

@Component
@RequiredArgsConstructor
public class HisService {
    private final DeviceService deviceService;
    private final QueryHisDataCommonService queryHisDataCommonService;

    public Map<String,List<OpenApiHisDataVO>> getYcHisData(EmsHisDataRequestVO<HisDataVO> requestVO){
        //hisDataVO 转 DitDataVO
        List<DitDataVO> ditDataVOList = requestVO.getHisDataVOS().stream().map(d-> DitDataVO.builder()
                .initDeviceCode(d.getInitDeviceCode()).dit(d.getPid().replace(d.getInitDeviceCode() + SysConstant.SPOT,""))
                .ditType(DitTypeEnum.YC.getCode()).build()).collect(Collectors.toList());
        List<OpenApiHisDataVO> dataVOList = queryHisDataCommonService.selectHisDataByDitDataList(requestVO.getStartTime(), requestVO.getEndTime(), ditDataVOList);
        if(CollectionUtils.isEmpty(dataVOList)){
            return Maps.newHashMap();
        }
        Map<String,List<OpenApiHisDataVO>> resultMap = Maps.newHashMap();
        dataVOList.stream().collect(Collectors.groupingBy(d->d.getPid(), LinkedHashMap::new,Collectors.toList())).forEach((k, v)->{
            if(requestVO.getTimeIntervalType() != null){
                TimeIntervalType intervalTypeEnum = TimeIntervalType.fromCode(requestVO.getTimeIntervalType());
                //按照时间颗粒度清洗数据
                v = dealHisDataByTimeGranularity(requestVO.getStartTime(),intervalTypeEnum.getMilliseconds(),v);
            }
            resultMap.put(k,v);
        });
        return resultMap;
    }

    /**
     * 获取实时数据的断面数据
     * @param jsonData
     * @return
     */
    public List<OpenApiHisDataVO> getSvgSectionData(Long sectionTime,String jsonData){
        //需要查询的点号有哪些
        List<HisDataVO> hisDataVOList = this.getHisDataListBySvgJSON(jsonData);
        return queryHisDataCommonService.selectFlashSectionData(sectionTime,hisDataVOList);
    }

    public Map<Long,List<OpenApiHisDataVO>> getSvgHisData(Long startTime,Long endTime,String jsonData){
        //需要查询的点号有哪些
        List<HisDataVO> searchData = this.getHisDataListBySvgJSON(jsonData);
        List<OpenApiHisDataVO> hisDataList = queryHisDataCommonService.selectFlashHisData(startTime,endTime,searchData);
        if(CollectionUtils.isEmpty(hisDataList)){
            return Collections.emptyMap();
        }
        return hisDataList.stream().collect(Collectors.groupingBy(d->d.getTime()));
    }

    public List<DitHisDataVO> getHisDataByDitDataList(Long startTime, Long endTime, Integer timeIntervalType,List<DitDataVO> ditDataVOList){
        Map<String,DitDataVO> ditDataVOMap = ditDataVOList.stream().collect(Collectors.toMap(d->d.getInitDeviceCode() + SysConstant.SPOT + d.getDit(),p->p,(p1,p2)->p1));
        List<DitHisDataVO> result = Lists.newArrayList();
        List<OpenApiHisDataVO> dataVOList = queryHisDataCommonService.selectHisDataByDitDataList(startTime, endTime, ditDataVOList);
        if(CollectionUtils.isEmpty(dataVOList)){
            return result;
        }
        List<DitDataExtraVO> extraVOList = deviceService.getDitExtraByDitDataList(ditDataVOList);
        Map<String,DitDataExtraVO> extraMap = extraVOList.stream().collect(Collectors.toMap(d->d.getInitDeviceCode() + SysConstant.SPOT + d.getDit(),p->p,(p1,p2)->p1));
        dataVOList.stream().collect(Collectors.groupingBy(d->d.getPid(), LinkedHashMap::new,Collectors.toList())).forEach((k, v)->{
            DitDataVO ditDataVO = ditDataVOMap.get(k);
            DitDataExtraVO extraVO = extraMap.get(k);
            if(timeIntervalType != null){
                TimeIntervalType intervalTypeEnum = TimeIntervalType.fromCode(timeIntervalType);
                //按照时间颗粒度清洗数据
                v = dealHisDataByTimeGranularity(startTime,intervalTypeEnum.getMilliseconds(),v);
            }
            result.add(DitHisDataVO.builder()
                    .initDeviceCode(ditDataVO.getInitDeviceCode())
                    .dit(ditDataVO.getDit()).ditType(ditDataVO.getDitType()).hisDataList(v)
                    .ditName(extraVO==null?null:extraVO.getDitName())
                    .unit(extraVO==null?null:extraVO.getUnit())
                    .build());
        });
        return result;
    }

    public List<TimeSeparation> getTimeSeparation(Long startTime, Long endTime, List<DitDataVO> ditDataVOList,Long separateTime){
        List<OpenApiHisDataVO> dataVOList = queryHisDataCommonService.selectHisDataByDitDataList(startTime, endTime, ditDataVOList);
        if(CollectionUtils.isEmpty(dataVOList)){
            return Collections.emptyList();
        }
        Long start = DateTimeUtil.getStartOfHour(new Date(startTime));
        boolean useFlag = false;
        List<TimeSeparation> result = Lists.newArrayList();
        //按照时间升序排序，在进行循环
        dataVOList = dataVOList.stream().sorted(Comparator.comparing(OpenApiHisDataVO::getTime)).collect(Collectors.toList());
        for (OpenApiHisDataVO d : dataVOList){
            if(d.getTime() < start){
                continue;
            }else {
                //为了防止某个值的时间跳过了好几个时间段，需要循环直到end大于该数据的结束时间
                while ((start + separateTime) < d.getTime()){
                    start = start + separateTime;
                    useFlag = false;
                }
                if(!useFlag){
                    //为了保证开始时间与其他的结束时间错开,这里结束时间减1毫秒
                    result.add(TimeSeparation.builder().startTime(start).endTime(start + separateTime-1).build());
                    useFlag = true;
                }
            }
        }
        return result;
    }

    private List<HisDataVO> getHisDataListBySvgJSON(String jsonData){
        List<HisDataVO> hisDataVOList = Lists.newArrayList();
        //String[0] : deviceCode ,String[1] : dit, String[2] : measureType
        List<String[]> list = JSON.parseArray(jsonData,String[].class);
        list.stream().forEach(d->{
            hisDataVOList.add(HisDataVO.builder()
                    .initDeviceCode(d[0]).pid(d[0] + SysConstant.SPOT + d[1])
                    .measureType(d.length>2?Integer.parseInt(d[2]):MeasureType.yc.getCode())
                    .build());
        });
        return hisDataVOList;
    }

    /**
     * 按照时间颗粒度清洗历史数据
     * @param startTime : 开始时间(时间颗粒度对应的第一个时间戳)
     * @param increaseTime : 时间颗粒度对应的毫秒级数据
     * @param hisDataList :  历史数据(只能是一个点号的历史数据,按照时间正序排序)
     * @return
     */
    private static List<OpenApiHisDataVO> dealHisDataByTimeGranularity(Long startTime,Long increaseTime,List<OpenApiHisDataVO> hisDataList){
        if(CollectionUtils.isEmpty(hisDataList)){
            return Collections.emptyList();
        }
        Map<Object,OpenApiHisDataVO> groupMap = hisDataList.stream().collect(Collectors.groupingBy(d-> (d.getTime()-startTime)/increaseTime,
                Collectors.collectingAndThen(Collectors.toList(), list -> list.stream().min(Comparator.comparingLong(OpenApiHisDataVO::getTime)).get())));
        return groupMap.values().stream().sorted(Comparator.comparing(OpenApiHisDataVO::getTime)).collect(Collectors.toList());
    }

}
